package cc.shacocloud.mirage.utils.converter;

import cc.shacocloud.mirage.utils.ClassUtil;
import cc.shacocloud.mirage.utils.MethodParameter;
import cc.shacocloud.mirage.utils.ResolvableType;
import cc.shacocloud.mirage.utils.Utils;
import cc.shacocloud.mirage.utils.annotation.AnnotatedElementUtils;
import cc.shacocloud.mirage.utils.collection.ArrayUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

/**
 * 关于要转换的类型描述符
 */
public class TypeDescriptor implements Serializable {
    
    private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
    
    private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<>(32);
    
    private static final Class<?>[] CACHED_COMMON_TYPES = {
            boolean.class, Boolean.class, byte.class, Byte.class, char.class, Character.class,
            double.class, Double.class, float.class, Float.class, int.class, Integer.class,
            long.class, Long.class, short.class, Short.class, String.class, Object.class};
    
    static {
        for (Class<?> preCachedClass : CACHED_COMMON_TYPES) {
            commonTypesCache.put(preCachedClass, valueOf(preCachedClass));
        }
    }
    
    
    private final Class<?> type;
    
    private final ResolvableType resolvableType;
    
    private final AnnotatedElementAdapter annotatedElement;
    
    
    /**
     * 从{@link MethodParameter}创建一个新的类型描述符
     * <p>
     * 当源或目标转换点是构造函数参数、方法参数或方法返回值时，请使用此构造函数。
     */
    public TypeDescriptor(MethodParameter methodParameter) {
        this.resolvableType = ResolvableType.forMethodParameter(methodParameter);
        this.type = this.resolvableType.resolve(methodParameter.getNestedParameterType());
        this.annotatedElement = new AnnotatedElementAdapter(methodParameter.getParameterIndex() == -1 ?
                methodParameter.getMethodAnnotations() : methodParameter.getParameterAnnotations());
    }
    
    /**
     * 从一个{@link Field}创建一个新的类型描述符
     * <p>
     * 当源或目标转换点是一个字段时，使用这个构造函数
     */
    public TypeDescriptor(Field field) {
        this.resolvableType = ResolvableType.forField(field);
        this.type = this.resolvableType.resolve(field.getType());
        this.annotatedElement = new AnnotatedElementAdapter(field.getAnnotations());
    }
    
    /**
     * 从一个{@link ResolvableType}创建一个新的类型描述符
     * <p>
     * 这个构造函数在内部使用，也可能被支持具有扩展类型系统的非Java语言的子类使用
     *
     * @param resolvableType 可解决的类型
     * @param type           支持的类型
     * @param annotations    类型注释
     */
    public TypeDescriptor(ResolvableType resolvableType,
                          @Nullable Class<?> type,
                          @Nullable Annotation[] annotations) {
        this.resolvableType = resolvableType;
        this.type = (type != null ? type : resolvableType.toClass());
        this.annotatedElement = new AnnotatedElementAdapter(annotations);
    }
    
    /**
     * 为一个对象创建一个新的类型描述符。
     * <p>在要求转换系统将一个源对象转换为另一种类型之前，使用这个工厂方法对其进行反省,转换系统将其转换为另一种类型。
     * <p>如果提供的对象是{@code null}，返回{@code null}，否则调用 {@link #valueOf(Class)}来从该对象的类中建立一个TypeDescriptor。
     *
     * @param source 源对象
     * @return 类型描述符
     */
    @Nullable
    public static TypeDescriptor forObject(@Nullable Object source) {
        return (source != null ? valueOf(source.getClass()) : null);
    }
    
    /**
     * 从给定的类型创建一个新的类型描述符
     * <p>使用这个指示转换系统将一个对象转换为一个 特定的目标类型，当没有类型的位置，如方法参数或字段来提供额外的转换环境。
     * <p>一般来说，更倾向于使用{@link #forObject(Object)}来构建类型描述符，因为它可以处理{@code null}对象的情况。
     *
     * @param type 类（可以用{@code null}来表示{@code Object.class}）
     * @return 相应的类型描述符
     */
    public static @NotNull TypeDescriptor valueOf(@Nullable Class<?> type) {
        if (type == null) {
            type = Object.class;
        }
        TypeDescriptor desc = commonTypesCache.get(type);
        return (desc != null ? desc : new TypeDescriptor(ResolvableType.forClass(type), null, null));
    }
    
    /**
     * 从一个{@link java.util.Collection}类型创建一个新的类型描述符。
     * <p>
     * 对于转换为类型化的集合是有用的。
     * <p>
     * 例如，一个{@code List<String>}可以通过转换为一个 {@code List<EmailAddress>}通过转换到一个用这个方法构建的targetType。
     * 构建这样一个{@code TypeDescriptor}的方法调用将看起来像像这样 {@code collection(List.class, TypeDescriptor.valueOf(EmailAddress.class));}。
     *
     * @param collectionType        集合类型，它必须实现{@link Collection}
     * @param elementTypeDescriptor 一个关于集合元素类型的描述符
     * @return 类型描述符
     */
    @Contract("_, _ -> new")
    public static @NotNull TypeDescriptor collection(@NotNull Class<?> collectionType,
                                                     @Nullable TypeDescriptor elementTypeDescriptor) {
        if (!Collection.class.isAssignableFrom(collectionType)) {
            throw new IllegalArgumentException("collectionType 必须是[java.util.Collection]的子类");
        }
        ResolvableType element = (elementTypeDescriptor != null ? elementTypeDescriptor.resolvableType : null);
        return new TypeDescriptor(ResolvableType.forClassWithGenerics(collectionType, element), null, null);
    }
    
    /**
     * 从一个{@link java.util.Map}类型创建一个新的类型描述符。
     * <p>
     * 对于转换为类型化的Maps来说是有用的。
     * <p>
     * 例如，一个Map&lt;String, String&gt;可以转换为一个Map&lt;Id, EmailAddress&gt;
     * 通过转换到一个用这个方法构建的targetType。
     * 构建这样一个TypeDescriptor的方法调用将看起来像。
     * <pre class="code">
     *    map(Map.class, TypeDescriptor.valueOf(Id.class), TypeDescriptor.valueOf(EmailAddress.class))。
     *  </pre>
     *
     * @param mapType             地图类型，它必须实现{@link Map}。
     * @param keyTypeDescriptor   地图键类型的描述符，用于转换地图键。
     * @param valueTypeDescriptor 地图的值类型，用于转换地图值。
     * @return 地图类型描述符
     */
    @Contract("_, _, _ -> new")
    public static @NotNull TypeDescriptor map(@NotNull Class<?> mapType,
                                              @Nullable TypeDescriptor keyTypeDescriptor,
                                              @Nullable TypeDescriptor valueTypeDescriptor) {
        if (!Map.class.isAssignableFrom(mapType)) {
            throw new IllegalArgumentException("mapType 必须是[java.util.Map]的子类");
        }
        ResolvableType key = (keyTypeDescriptor != null ? keyTypeDescriptor.resolvableType : null);
        ResolvableType value = (valueTypeDescriptor != null ? valueTypeDescriptor.resolvableType : null);
        return new TypeDescriptor(ResolvableType.forClassWithGenerics(mapType, key, value), null, null);
    }
    
    /**
     * 创建一个新的类型描述符，作为指定类型的一个数组。
     * <p>例如，创建一个{@code Map<String,String>[]}使用。
     * <pre class="code">
     *      TypeDescriptor.array(TypeDescriptor.map(Map.class, TypeDescriptor.value(String.class), TypeDescriptor.value(String.class))。
     * </pre>
     *
     * @param elementTypeDescriptor {@link TypeDescriptor}或{@code null}
     * @return 一个数组{@link TypeDescriptor}，如果{@code elementTypeDescriptor}是{@code null}的话返回{@code null}
     */
    @Nullable
    public static TypeDescriptor array(@Nullable TypeDescriptor elementTypeDescriptor) {
        if (elementTypeDescriptor == null) {
            return null;
        }
        return new TypeDescriptor(ResolvableType.forArrayComponent(elementTypeDescriptor.resolvableType),
                null, elementTypeDescriptor.getAnnotations());
    }
    
    /**
     * 为方法参数中声明的嵌套类型创建一个类型描述符。
     * <p>
     * 例如，如果methodParameter是一个{@code List<String>}，并且嵌套级别是1，嵌套类型描述符将是String.class。
     * <p>
     * 如果methodParameter是一个{@code List<List<String>}，并且嵌套级别是2，那么嵌套的类型描述符就是String.class。
     * 级别是2，嵌套的类型描述符也将是String.class。
     * <p>
     * 如果methodParameter是一个{@code Map<Integer, String>}并且嵌套的级别是1，嵌套的类型描述符将是String，由map值派生。
     * <p>
     * 如果methodParameter是一个{@code List<Map<Integer, String>}并且嵌套级别是2，那么嵌套的类型描述符将是String，由map值派生。
     * 嵌套级别是2，嵌套类型描述符将是String，由map值派生。
     * <p>
     * 如果一个嵌套类型因为没有被声明而无法获得，则返回{@code null}。
     * 例如，如果方法参数是{@code List<?>}，返回的嵌套类型将是{@code List<?>} 返回的描述符将是{@code null}。
     *
     * @param methodParameter 方法参数，其嵌套级别为 1
     * @param nestingLevel    集合/数组元素的嵌套级别或方法参数内的映射键/值声明
     * @return 在指定的嵌套层次上的嵌套类型描述符。如果无法获得，则{@code null}。
     * @throws IllegalArgumentException 如果输入的嵌套级别 {@link MethodParameter}参数不是1，或者到指定嵌套级别的类型不是集合、
     *                                  数组或地图类型, 指定的嵌套级别不属于集合、数组或地图类型。
     */
    @Nullable
    public static TypeDescriptor nested(MethodParameter methodParameter, int nestingLevel) {
        if (methodParameter.getNestingLevel() != 1) {
            throw new IllegalArgumentException("MethodParameter的嵌套级别必须是1：使用nestingLevel参数为嵌套类型遍历指定所需的nestingLevel。");
        }
        return nested(new TypeDescriptor(methodParameter), nestingLevel);
    }
    
    /**
     * 为字段内声明的嵌套类型创建一个类型描述符。
     * <p>
     * 例如，如果field是一个{@code List<String>}，并且嵌套级别是1，嵌套类型描述符将是String.class。
     * <p>
     * 如果field是一个{@code List<List<String>}，并且嵌套级别是2，那么嵌套的类型描述符就是String.class。
     * 级别是2，嵌套的类型描述符也将是String.class。
     * <p>
     * 如果field是一个{@code Map<Integer, String>}并且嵌套的级别是1，嵌套的类型描述符将是String，由map值派生。
     * <p>
     * 如果field是一个{@code List<Map<Integer, String>}并且嵌套级别是2，那么嵌套的类型描述符将是String，由map值派生。
     * 嵌套级别是2，嵌套类型描述符将是String，由map值派生。
     * <p>
     * 如果一个嵌套类型因为没有被声明而无法获得，则返回{@code null}。
     * 例如，如果方法参数是{@code List<?>}，返回的嵌套类型将是{@code List<?>} 返回的描述符将是{@code null}。
     *
     * @param field        {@link Field}
     * @param nestingLevel 集合/数组元素的嵌套级别或方法参数内的映射键/值声明
     * @return 在指定的嵌套层次上的嵌套类型描述符。如果无法获得，则{@code null}。
     * @throws IllegalArgumentException 如果到指定嵌套级别的类型不属于集合、数组或地图类型
     */
    @Nullable
    public static TypeDescriptor nested(Field field, int nestingLevel) {
        return nested(new TypeDescriptor(field), nestingLevel);
    }
    
    @Nullable
    private static TypeDescriptor nested(@NotNull TypeDescriptor typeDescriptor, int nestingLevel) {
        ResolvableType nested = typeDescriptor.resolvableType;
        for (int i = 0; i < nestingLevel; i++) {
            if (Object.class != nested.getType()) {
                nested = nested.getNested(2);
            }
        }
        if (nested == ResolvableType.NONE) {
            return null;
        }
        return getRelatedIfResolvable(typeDescriptor, nested);
    }
    
    @Nullable
    private static TypeDescriptor getRelatedIfResolvable(TypeDescriptor source, ResolvableType type) {
        if (type.resolve() == null) {
            return null;
        }
        return new TypeDescriptor(type, null, source.getAnnotations());
    }
    
    /**
     * {@link #getType()}的变体，通过返回其对象包装类型来说明原始类型
     * <p>
     * 这对于希望规范化为基于对象的类型而不直接处理原始类型的转换服务实现是很有用的。
     */
    public Class<?> getObjectType() {
        return ClassUtil.resolvePrimitiveIfNecessary(getType());
    }
    
    /**
     * 这个 TypeDescriptor 所描述的支持类、方法参数、字段或属性的类型
     *
     * <p>
     * 按原样返回原始类型。请参阅{@link #getObjectType()}以了解此操作的变体，如果有必要，它可以将原始类型解析为其对应的对象类型。
     *
     * @see #getObjectType()
     */
    public Class<?> getType() {
        return this.type;
    }
    
    /**
     * 返回底层的{@link ResolvableType}
     */
    public ResolvableType getResolvableType() {
        return this.resolvableType;
    }
    
    /**
     * 返回描述符的基本来源
     * <p>
     * 将返回一个{@link Field}、 {@link MethodParameter}或{@link Type}，这取决于{@link TypeDescriptor} 的构造方式
     */
    public Object getSource() {
        return this.resolvableType.getSource();
    }
    
    /**
     * 缩小这个{@link TypeDescriptor}，将其类型设置为提供的值的类别。
     * <p>
     * 如果值是{@code null}，则不进行缩小，这个 TypeDescriptor 将被原样返回。
     * <p>
     * 设计成由绑定框架在读取属性、字段或方法返回值时调用。允许这些框架缩小TypeDescriptor的范围，从声明的属性、字段或方法的返回值类型中建立。
     * 例如，一个声明为{@code java.lang.Object}的字段将被缩小为{@code java.util.HashMap} 如果它被设置为{@code java.util.HashMap}值。
     * 然后，缩小的TypeDescriptor 可以被用来将HashMap转换为其他类型。注释和嵌套的类型上下文被缩小的副本所保留。
     *
     * @param value 用于缩小该类型描述符范围的值
     * @return 这个 TypeDescriptor 缩小了（返回一个副本，其类型更新为所提供值的类）。
     */
    public TypeDescriptor narrow(@Nullable Object value) {
        if (value == null) {
            return this;
        }
        ResolvableType narrowed = ResolvableType.forType(value.getClass(), getResolvableType());
        return new TypeDescriptor(narrowed, value.getClass(), getAnnotations());
    }
    
    /**
     * 将这个{@link TypeDescriptor}投给一个超类或实现的接口，保留注释和嵌套的类型上下文。
     *
     * @param superType 要转换的超类型（可以是{@code null}）
     * @return 一个新的 TypeDescriptor ，用于向上转换的类型
     * @throws IllegalArgumentException 如果该类型不能被分配给超类
     */
    @Nullable
    public TypeDescriptor upcast(@Nullable Class<?> superType) {
        if (superType == null) {
            return null;
        }
        
        Class<?> type = getType();
        if (!ClassUtil.isAssignable(superType, type)) {
            throw new IllegalArgumentException(superType + " 不是 " + type + " 的超类或者父类！");
        }
        
        return new TypeDescriptor(getResolvableType().as(superType), superType, getAnnotations());
    }
    
    /**
     * 返回该类型的名称：完全合格的类名称
     */
    public String getName() {
        return getType().getTypeName();
    }
    
    /**
     * 这个类型是一个原始类型吗？
     */
    public boolean isPrimitive() {
        return getType().isPrimitive();
    }
    
    /**
     * 返回与该类型描述符相关的注释，如果有的话。
     *
     * @return 注释，如果没有，则为空数组
     */
    public Annotation[] getAnnotations() {
        return this.annotatedElement.getAnnotations();
    }
    
    /**
     * 确定这个类型描述符是否有指定的注释
     *
     * @param annotationType 注释类型
     * @return 如果存在则返回 true
     */
    public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
        if (this.annotatedElement.isEmpty()) {
            return false;
        }
        return AnnotatedElementUtils.hasAnnotation(this.annotatedElement, annotationType);
    }
    
    /**
     * 获取此类型描述符上的指定{@code annotationType}的注释
     *
     * @param annotationType 注释类型
     * @return 注释，如果该类型描述符上不存在这样的注释，则{@code null}
     */
    @Nullable
    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
        if (this.annotatedElement.isEmpty()) {
            return null;
        }
        
        return AnnotatedElementUtils.getAnnotation(this.annotatedElement, annotationType);
    }
    
    /**
     * 如果这个类型描述符的对象可以被分配到给定类型描述符所描述的位置，则返回true。
     * <p>
     * 例如，{@code valueOf(String.class).isAssignableTo(valueOf(CharSequence.class))} 返回{@code true}，
     * 因为一个字符串值可以被分配给CharSequence变量。
     * 另一方面，{@code valueOf(Number.class).isAssignableTo(valueOf(Integer.class))} 返回{@code false}，
     * 因为虽然所有的整数是数字，但不是所有数字是整数。
     * * <p>
     * 对于数组、集合和地图，如果声明了元素和键/值类型，就会被检查。
     * 例如，一个List&lt;String&gt;字段的值可以分配给一个Collection&lt;CharSequence&gt;字段，但是List&lt;Number&gt;不能分配给List&lt;Integer&gt;。
     *
     * @return {@code true} 如果这个类型可以分配给所提供的*类型描述符所代表的类型
     * @see #getObjectType()
     */
    public boolean isAssignableTo(@NotNull TypeDescriptor typeDescriptor) {
        boolean typesAssignable = typeDescriptor.getObjectType().isAssignableFrom(getObjectType());
        if (!typesAssignable) {
            return false;
        }
        if (isArray() && typeDescriptor.isArray()) {
            return isNestedAssignable(getElementTypeDescriptor(), typeDescriptor.getElementTypeDescriptor());
        } else if (isCollection() && typeDescriptor.isCollection()) {
            return isNestedAssignable(getElementTypeDescriptor(), typeDescriptor.getElementTypeDescriptor());
        } else if (isMap() && typeDescriptor.isMap()) {
            return isNestedAssignable(getMapKeyTypeDescriptor(), typeDescriptor.getMapKeyTypeDescriptor()) &&
                    isNestedAssignable(getMapValueTypeDescriptor(), typeDescriptor.getMapValueTypeDescriptor());
        } else {
            return true;
        }
    }
    
    private boolean isNestedAssignable(@Nullable TypeDescriptor nestedTypeDescriptor,
                                       @Nullable TypeDescriptor otherNestedTypeDescriptor) {
        
        return (nestedTypeDescriptor == null || otherNestedTypeDescriptor == null ||
                nestedTypeDescriptor.isAssignableTo(otherNestedTypeDescriptor));
    }
    
    /**
     * 这个类型是一个{@link Collection}类型吗？
     */
    public boolean isCollection() {
        return Collection.class.isAssignableFrom(getType());
    }
    
    /**
     * 这个类型是一个数组类型吗？
     */
    public boolean isArray() {
        return getType().isArray();
    }
    
    /**
     * 如果该类型是一个数组，返回数组的组件类型。
     * 如果该类型是一个{@code Stream}，则返回该流的组件类型。
     * 如果该类型是一个{@link Collection}并且是参数化的，则返回该集合的元素类型
     * 如果集合没有被参数化，则返回{@code null}，表明元素类型没有被声明
     *
     * @return 数组组件类型或集合元素类型，如果该类型不是数组类型或{@code java.util.Collection}或其元素类型未被参数化，则{@code null}。
     * @see #elementTypeDescriptor(Object)
     */
    @Nullable
    public TypeDescriptor getElementTypeDescriptor() {
        if (getResolvableType().isArray()) {
            return new TypeDescriptor(getResolvableType().getComponentType(), null, getAnnotations());
        }
        if (Stream.class.isAssignableFrom(getType())) {
            return getRelatedIfResolvable(this, getResolvableType().as(Stream.class).getGeneric(0));
        }
        return getRelatedIfResolvable(this, getResolvableType().asCollection().getGeneric(0));
    }
    
    /**
     * 如果这个类型是一个{@link Collection}或一个数组，从提供的集合或数组元素中创建一个元素TypeDescriptor
     * <p>
     * 将{@link #getElementTypeDescriptor() elementType}属性缩小到所提供的集合或数组元素的类别。
     * 例如，如果这描述了一个 {@code java.util.List<java.lang.Number>} 并且元素参数是一个 {@code java.lang.Integer},
     * 返回的TypeDescriptor将是 {@code java.lang.Integer}.
     * 如果这描述了一个{@code java.util.List<?>}并且元素参数是一个 {@code java.lang.Integer}，
     * 返回的 TypeDescriptor 也是{@code java.lang.Integer}
     * <p>
     * 注释和嵌套的类型上下文将被保留在被返回的缩小的 TypeDescriptor中。
     *
     * @param element 集合或数组元素
     * @return 一个元素类型描述符，缩小到所提供元素的类型。
     * @see #getElementTypeDescriptor()
     * @see #narrow(Object)
     */
    @Nullable
    public TypeDescriptor elementTypeDescriptor(Object element) {
        return narrow(element, getElementTypeDescriptor());
    }
    
    /**
     * 这个类型是一个{@link Map}类型吗？
     */
    public boolean isMap() {
        return Map.class.isAssignableFrom(getType());
    }
    
    /**
     * 如果这个类型是{@link Map}，并且它的键类型是参数化的，返回地图的键类型。
     * 如果Map的键类型没有被参数化，返回{@code null}，表示该键类型没有被声明。
     *
     * @return Map的关键类型，或者{@code null}如果这个类型是一个Map 但是它的关键类型没有被参数化
     * @throws IllegalStateException 如果该类型不是{@code java.util.Map}，则抛出该例外
     */
    @Nullable
    public TypeDescriptor getMapKeyTypeDescriptor() {
        if (!isMap()) {
            throw new IllegalStateException("这不是一个 Map 类型描述，无法调用该方法！");
        }
        return getRelatedIfResolvable(this, getResolvableType().asMap().getGeneric(0));
    }
    
    /**
     * 如果这个类型是一个{@link Map}，则从提供的地图键中创建一个mapKey {@link TypeDescriptor}
     * <p>
     * 将{@link #getMapKeyTypeDescriptor() mapKeyType}属性缩小到所提供的地图键的类别。
     * 例如，如果这描述了一个  {@code java.util.Map<java.lang.Number, java.lang.String>}并且键参数是一个 {@code java.lang.Integer}，
     * 返回的TypeDescriptor将是 {@code java.lang.Integer}。
     * 如果这描述了一个{@code java.util.Map<?, ?>} 并且关键参数是一个{@code java.lang.Integer}，
     * 返回的 TypeDescriptor也将是{@code java.lang.Integer}。
     * <p>
     * 注释和嵌套的类型上下文将被保留在被返回的缩小的 TypeDescriptor中。
     *
     * @param mapKey 地图键
     * @return 地图键类型描述符
     * @throws IllegalStateException 如果该类型不是{@code java.util.Map}，则抛出该例外
     * @see #narrow(Object)
     */
    @Nullable
    public TypeDescriptor getMapKeyTypeDescriptor(Object mapKey) {
        return narrow(mapKey, getMapKeyTypeDescriptor());
    }
    
    /**
     * 如果这个类型是一个{@link Map}，并且它的值类型是参数化的，返回map的值类型。
     * <p>
     * 如果Map的值类型没有被参数化，则返回{@code null} 表示该值类型没有被声明。
     *
     * @return Map值类型， 如果这个类型是一个Map 但是它的值类型没有被参数化，返回{@code null}
     * @throws IllegalStateException 如果该类型不是{@code java.util.Map}，则抛出该例外
     */
    @Nullable
    public TypeDescriptor getMapValueTypeDescriptor() {
        if (!isMap()) {
            throw new IllegalStateException("这不是一个 Map 类型描述，无法调用该方法！");
        }
        return getRelatedIfResolvable(this, getResolvableType().asMap().getGeneric(1));
    }
    
    /**
     * 如果这个类型是一个{@link Map}，则从提供的地图值中创建一个mapValue {@link TypeDescriptor}
     * <p>
     * 将{@link #getMapValueTypeDescriptor() mapValueType}属性缩小到所提供的地图值的类别。
     * 例如，如果这描述了一个 {@code java.util.Map<java.lang.String, java.lang.Number>}并且值参数是一个 {@code java.lang.Integer}，
     * 返回的TypeDescriptor将是 * {@code java.lang.Integer}。
     * 如果这描述了一个{@code java.util.Map<?, ?>} 并且值参数是一个{@code java.lang.Integer}，
     * 返回的 TypeDescriptor 也将是{@code java.lang.Integer}。
     * <p>
     * 注释和嵌套的类型上下文将被保留在被返回的缩小的 TypeDescriptor中。
     *
     * @param mapValue the map value
     * @return the map value type descriptor
     * @throws IllegalStateException if this type is not a {@code java.util.Map}
     * @see #narrow(Object)
     */
    @Nullable
    public TypeDescriptor getMapValueTypeDescriptor(Object mapValue) {
        return narrow(mapValue, getMapValueTypeDescriptor());
    }
    
    @Nullable
    private TypeDescriptor narrow(@Nullable Object value, @Nullable TypeDescriptor typeDescriptor) {
        if (typeDescriptor != null) {
            return typeDescriptor.narrow(value);
        }
        if (value != null) {
            return narrow(value);
        }
        return null;
    }
    
    @Override
    public boolean equals(@Nullable Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof TypeDescriptor)) {
            return false;
        }
        TypeDescriptor otherDesc = (TypeDescriptor) other;
        if (getObjectType() != otherDesc.getObjectType()) {
            return false;
        }
        if (!annotationsMatch(otherDesc)) {
            return false;
        }
        if (isCollection() || isArray()) {
            return Utils.nullSafeEquals(getElementTypeDescriptor(), otherDesc.getElementTypeDescriptor());
        } else if (isMap()) {
            return (Utils.nullSafeEquals(getMapKeyTypeDescriptor(), otherDesc.getMapKeyTypeDescriptor()) &&
                    Utils.nullSafeEquals(getMapValueTypeDescriptor(), otherDesc.getMapValueTypeDescriptor()));
        } else {
            return true;
        }
    }
    
    private boolean annotationsMatch(@NotNull TypeDescriptor otherDesc) {
        Annotation[] anns = getAnnotations();
        Annotation[] otherAnns = otherDesc.getAnnotations();
        if (anns == otherAnns) {
            return true;
        }
        if (anns.length != otherAnns.length) {
            return false;
        }
        if (anns.length > 0) {
            for (int i = 0; i < anns.length; i++) {
                if (!annotationEquals(anns[i], otherAnns[i])) {
                    return false;
                }
            }
        }
        return true;
    }
    
    private boolean annotationEquals(Annotation ann, Annotation otherAnn) {
        // Annotation.equals是反射性的，而且相当慢，所以我们先检查身份和代理类型。
        return (ann == otherAnn || (ann.getClass() == otherAnn.getClass() && ann.equals(otherAnn)));
    }
    
    @Override
    public int hashCode() {
        return getType().hashCode();
    }
    
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        for (Annotation ann : getAnnotations()) {
            builder.append('@').append(ann.annotationType().getName()).append(' ');
        }
        builder.append(getResolvableType());
        return builder.toString();
    }
    
    /**
     * 适配器类，用于将{@code TypeDescriptor}的注释作为{@link AnnotatedElement}公开，
     * 尤其是向{@link AnnotatedElementUtils}公开。
     *
     * @see AnnotatedElementUtils#hasAnnotation(AnnotatedElement, Class)
     * @see AnnotatedElementUtils#getAnnotation(AnnotatedElement, Class)
     */
    private class AnnotatedElementAdapter implements AnnotatedElement, Serializable {
        
        @Nullable
        private final Annotation[] annotations;
        
        public AnnotatedElementAdapter(@Nullable Annotation[] annotations) {
            this.annotations = annotations;
        }
        
        @Override
        public boolean isAnnotationPresent(@NotNull Class<? extends Annotation> annotationClass) {
            for (Annotation annotation : getAnnotations()) {
                if (annotation.annotationType() == annotationClass) {
                    return true;
                }
            }
            return false;
        }
        
        @Override
        @Nullable
        @SuppressWarnings("unchecked")
        public <T extends Annotation> T getAnnotation(@NotNull Class<T> annotationClass) {
            for (Annotation annotation : getAnnotations()) {
                if (annotation.annotationType() == annotationClass) {
                    return (T) annotation;
                }
            }
            return null;
        }
        
        @Override
        public Annotation[] getAnnotations() {
            return (this.annotations != null ? this.annotations.clone() : EMPTY_ANNOTATION_ARRAY);
        }
        
        @Override
        public Annotation[] getDeclaredAnnotations() {
            return getAnnotations();
        }
        
        public boolean isEmpty() {
            return ArrayUtil.isEmpty(this.annotations);
        }
        
        @Override
        public boolean equals(@Nullable Object other) {
            return (this == other || (other instanceof AnnotatedElementAdapter &&
                    Arrays.equals(this.annotations, ((AnnotatedElementAdapter) other).annotations)));
        }
        
        @Override
        public int hashCode() {
            return Arrays.hashCode(this.annotations);
        }
        
        @Override
        public String toString() {
            return TypeDescriptor.this.toString();
        }
    }
    
}
